/*
Copyright 2018-2024 New Vector Ltd.
Copyright 2017 Vector Creations Ltd
Copyright 2016 OpenMarket Ltd

SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
 */

#import "RoomMemberDetailsViewController.h"

#import "GeneratedInterface-Swift.h"

#import "RoomMemberTitleView.h"

#import "AvatarGenerator.h"
#import "Tools.h"

#import "TableViewCellWithButton.h"
#import "RoomTableViewCell.h"
#import "MXRoom+Riot.h"

#define TABLEVIEW_ROW_CELL_HEIGHT         46
#define TABLEVIEW_SECTION_HEADER_HEIGHT   28

@interface RoomMemberDetailsViewController () <UIGestureRecognizerDelegate, DeviceTableViewCellDelegate, RoomMemberTitleViewDelegate, KeyVerificationCoordinatorBridgePresenterDelegate, UserVerificationCoordinatorBridgePresenterDelegate>
{
    RoomMemberTitleView* memberTitleView;
    
    NSInteger securityIndex;
    NSArray<NSNumber*> *securityActionsArray;
    
    /**
     List of the admin actions on this member.
     */
    NSMutableArray<NSNumber*> *adminActionsArray;
    NSInteger adminToolsIndex;
    
    /**
     List of the basic actions on this member.
     */
    NSMutableArray<NSNumber*> *otherActionsArray;
    NSInteger otherActionsIndex;
    
    /**
     List of the direct chats (room ids) with this member.
     */
    NSMutableArray<NSString*> *directChatsArray;
    NSInteger directChatsIndex;
    
    /**
     Devices
     */
    NSArray<MXDeviceInfo *> *devicesArray;
    NSInteger devicesIndex;
    KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter;

    
    /**
     Observe UIApplicationWillChangeStatusBarOrientationNotification to hide/show bubbles bg.
     */
    id UIApplicationWillChangeStatusBarOrientationNotificationObserver;
    
    /**
     Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change.
     */
    id kThemeServiceDidChangeThemeNotificationObserver;
    
    /**
     The current visibility of the status bar in this view controller.
     */
    BOOL isStatusBarHidden;
}

@property (weak, nonatomic) IBOutlet UIView *roomMemberAvatarHeaderBackground;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *roomMemberAvatarHeaderBackgroundHeightConstraint;

@property (weak, nonatomic) IBOutlet UIView *memberHeaderView;
@property (weak, nonatomic) IBOutlet UIView *roomMemberAvatarMask;
@property (weak, nonatomic) IBOutlet UIImageView *roomMemberAvatarBadgeImageView;

@property (weak, nonatomic) IBOutlet UILabel *roomMemberNameLabel;
@property (weak, nonatomic) IBOutlet UIView *roomMemberNameContainerView;

@property (weak, nonatomic) IBOutlet UILabel *roomMemberUserIdLabel;

@property (weak, nonatomic) IBOutlet UILabel *roomMemberStatusLabel;

@property (weak, nonatomic) IBOutlet UIImageView *bottomImageView;

@property (weak, nonatomic) IBOutlet UILabel *roomMemberPowerLevelLabel;
@property (weak, nonatomic) IBOutlet UIView *roomMemberPowerLevelContainerView;

@property(nonatomic) UserEncryptionTrustLevel encryptionTrustLevel;

@property(nonatomic, strong) UserVerificationCoordinatorBridgePresenter *userVerificationCoordinatorBridgePresenter;

@property(nonatomic) AnalyticsScreenTracker *screenTracker;

@end

@implementation RoomMemberDetailsViewController

#pragma mark - Class methods

+ (UINib *)nib
{
    return [UINib nibWithNibName:NSStringFromClass(self.class)
                          bundle:[NSBundle bundleForClass:self.class]];
}

+ (instancetype)roomMemberDetailsViewController
{
    return [[[self class] alloc] initWithNibName:NSStringFromClass(self.class)
                                          bundle:[NSBundle bundleForClass:self.class]];
}

#pragma mark -

- (void)finalizeInit
{
    [super finalizeInit];
    
    // Setup `MXKViewControllerHandling` properties
    self.enableBarTintColorStatusChange = NO;
    self.rageShakeManager = [RageShakeManager sharedManager];
    self.encryptionTrustLevel = UserEncryptionTrustLevelUnknown;
    
    adminActionsArray = [[NSMutableArray alloc] init];
    otherActionsArray = [[NSMutableArray alloc] init];
    directChatsArray = [[NSMutableArray alloc] init];
    
    // Keep visible the status bar by default.
    isStatusBarHidden = NO;
    
    self.screenTracker = [[AnalyticsScreenTracker alloc] initWithScreen:AnalyticsScreenUser];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    memberTitleView = [RoomMemberTitleView roomMemberTitleView];
    memberTitleView.delegate = self;
        
    // Define directly the navigation titleView with the custom title view instance. Do not use anymore a container.
    self.navigationItem.titleView = memberTitleView;    
    
    // Add tap to show the room member avatar in fullscreen
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
    tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
    [tap setNumberOfTouchesRequired:1];
    [tap setNumberOfTapsRequired:1];
    [tap setDelegate:self];
    [self.roomMemberAvatarMask addGestureRecognizer:tap];
    self.roomMemberAvatarMask.userInteractionEnabled = YES;
    
    // Need to listen to the tap gesture in the title view too.
    tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
    [tap setNumberOfTouchesRequired:1];
    [tap setNumberOfTapsRequired:1];
    [tap setDelegate:self];
    [memberTitleView.memberAvatarMask addGestureRecognizer:tap];
    memberTitleView.memberAvatarMask.userInteractionEnabled = YES;
    
    // Register collection view cell class
    [self.tableView registerClass:TableViewCellWithButton.class forCellReuseIdentifier:[TableViewCellWithButton defaultReuseIdentifier]];
    [self.tableView registerClass:RoomTableViewCell.class forCellReuseIdentifier:[RoomTableViewCell defaultReuseIdentifier]];
    [self.tableView registerClass:DeviceTableViewCell.class forCellReuseIdentifier:[DeviceTableViewCell defaultReuseIdentifier]];
    [self.tableView registerClass:MXKTableViewCell.class forCellReuseIdentifier:[MXKTableViewCell defaultReuseIdentifier]];
    
    // Hide line separators of empty cells
    self.tableView.tableFooterView = [[UIView alloc] init];
    
    // Enable self sizing cells
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    self.tableView.estimatedRowHeight = 50;
    
    // Observe UIApplicationWillChangeStatusBarOrientationNotification to hide/show bubbles bg.
    UIApplicationWillChangeStatusBarOrientationNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillChangeStatusBarOrientationNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
        
        NSNumber *orientation = (NSNumber*)(notif.userInfo[UIApplicationStatusBarOrientationUserInfoKey]);
        self.bottomImageView.hidden = (orientation.integerValue == UIInterfaceOrientationLandscapeLeft || orientation.integerValue == UIInterfaceOrientationLandscapeRight);
    }];
    
    // Observe user interface theme change.
    kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
        
        [self userInterfaceThemeDidChange];
        
    }];
}

- (void)userInterfaceThemeDidChange
{
    [ThemeService.shared.theme applyStyleOnNavigationBar:self.navigationController.navigationBar];
    self.navigationController.navigationBar.translucent = YES;

    self.activityIndicator.backgroundColor = ThemeService.shared.theme.overlayBackgroundColor;
    
    self.memberHeaderView.backgroundColor = ThemeService.shared.theme.baseColor;
    self.roomMemberNameLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
    self.roomMemberUserIdLabel.textColor = ThemeService.shared.theme.textPrimaryColor;

    self.roomMemberStatusLabel.textColor = ThemeService.shared.theme.tintColor;
    self.roomMemberPowerLevelLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
    
    // Check the table view style to select its bg color.
    self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? ThemeService.shared.theme.backgroundColor : ThemeService.shared.theme.headerBackgroundColor);
    self.view.backgroundColor = self.tableView.backgroundColor;
    self.tableView.separatorColor = ThemeService.shared.theme.lineBreakColor;
    
    if (self.tableView.dataSource)
    {
        [self.tableView reloadData];
    }

    [self setNeedsStatusBarAppearanceUpdate];
}

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return ThemeService.shared.theme.statusBarStyle;
}

- (BOOL)prefersStatusBarHidden
{
    // Return the current status bar visibility.
    return isStatusBarHidden;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    [self.screenTracker trackScreen];

    [self userInterfaceThemeDidChange];

    // Hide the bottom border of the navigation bar to display the expander header
    [self hideNavigationBarBorder:YES];
    
    // Handle here the bottom image visibility
    UIInterfaceOrientation screenOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    self.bottomImageView.hidden = (screenOrientation == UIInterfaceOrientationLandscapeLeft || screenOrientation == UIInterfaceOrientationLandscapeRight);
    
    [self refreshUserEncryptionTrustLevel];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    // Restore navigation bar display
    [self hideNavigationBarBorder:NO];
    
    self.bottomImageView.hidden = YES;
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
    // Restore navigation bar display
    [self hideNavigationBarBorder:NO];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(coordinator.transitionDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
        // Hide the bottom border of the navigation bar
        [self hideNavigationBarBorder:YES];
        
    });
}

- (void)destroy
{
    [super destroy];
    
    adminActionsArray = nil;
    otherActionsArray = nil;
    directChatsArray = nil;
    devicesArray = nil;
    
    if (UIApplicationWillChangeStatusBarOrientationNotificationObserver)
    {
        [[NSNotificationCenter defaultCenter] removeObserver:UIApplicationWillChangeStatusBarOrientationNotificationObserver];
        UIApplicationWillChangeStatusBarOrientationNotificationObserver = nil;
    }
    
    if (kThemeServiceDidChangeThemeNotificationObserver)
    {
        [[NSNotificationCenter defaultCenter] removeObserver:kThemeServiceDidChangeThemeNotificationObserver];
        kThemeServiceDidChangeThemeNotificationObserver = nil;
    }
    
    [memberTitleView removeFromSuperview];
    memberTitleView = nil;
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    
    // Check whether the title view has been created and rendered.
    if (memberTitleView && memberTitleView.superview)
    {
        // Adjust the header height by taking into account the actual position of the member avatar in title view
        // This position depends automatically on the screen orientation.
        CGPoint memberAvatarOriginInTitleView = memberTitleView.memberAvatarMask.frame.origin;
        CGPoint memberAvatarActualPosition = [memberTitleView convertPoint:memberAvatarOriginInTitleView toView:self.view];
        
        CGFloat avatarHeaderHeight = memberAvatarActualPosition.y + self.memberThumbnail.frame.size.height;
        if (_roomMemberAvatarHeaderBackgroundHeightConstraint.constant != avatarHeaderHeight)
        {
            _roomMemberAvatarHeaderBackgroundHeightConstraint.constant = avatarHeaderHeight;
            
            // Force the layout of the header
            [self.memberHeaderView layoutIfNeeded];
        }
    }
}

#pragma mark -

- (UIImage*)picturePlaceholder
{
    if (self.mxRoomMember)
    {
        // Use the vector style placeholder
        return [AvatarGenerator generateAvatarForMatrixItem:self.mxRoomMember.userId withDisplayName:self.mxRoomMember.displayname];
    }
    
    return [MXKTools paintImage:AssetImages.placeholder.image
                      withColor:ThemeService.shared.theme.tintColor];
}

- (void)updateMemberInfo
{
    if (self.mxRoomMember)
    {        
        self.roomMemberNameContainerView.hidden = !self.mxRoomMember.displayname;
        
        self.roomMemberNameLabel.text = self.mxRoomMember.displayname; 
        
        self.roomMemberUserIdLabel.text = self.mxRoomMember.userId;    
        
        // Update member power level
        MXWeakify(self);
        [self.mxRoom state:^(MXRoomState *roomState) {
            MXStrongifyAndReturnIfNil(self);

            MXRoomPowerLevels *powerLevels = [roomState powerLevels];
            NSInteger powerLevel = [roomState powerLevelOfUserWithUserID:self.mxRoomMember.userId];
            
            RoomPowerLevel roomPowerLevel = [RoomPowerLevelHelper roomPowerLevelFrom:powerLevel];
            
            switch (roomPowerLevel) {
                case RoomPowerLevelOwner:
                    self.roomMemberPowerLevelLabel.text = [VectorL10n roomMemberPowerLevelOwnerIn:self.mxRoom.summary.displayName];
                    self.roomMemberPowerLevelContainerView.hidden = NO;
                    break;
                case RoomPowerLevelAdmin:
                    self.roomMemberPowerLevelLabel.text = [VectorL10n roomMemberPowerLevelAdminIn:self.mxRoom.summary.displayName];
                    self.roomMemberPowerLevelContainerView.hidden = NO;
                    break;
                case RoomPowerLevelModerator:
                    self.roomMemberPowerLevelLabel.text = [VectorL10n roomMemberPowerLevelModeratorIn:self.mxRoom.summary.displayName];
                    self.roomMemberPowerLevelContainerView.hidden = NO;
                    break;
                default:
                    self.roomMemberPowerLevelLabel.text = nil;
                    self.roomMemberPowerLevelContainerView.hidden = YES;
                    break;
            }
        }];
        
        NSString* presenceText;
        
        NSString *userId = self.mxRoomMember.userId;
        
        if (userId)
        {
            MXUser *user = [self.mxRoom.mxSession userWithUserId:userId];
            presenceText = [Tools presenceText:user];
        }
        
        self.roomMemberStatusLabel.text = presenceText;
        
        self.roomMemberAvatarBadgeImageView.image = [EncryptionTrustLevelBadgeImageHelper userBadgeImageFor:self.encryptionTrustLevel];
        
        // Retrieve the existing direct chats
        [directChatsArray removeAllObjects];
        NSArray *directRoomIds = self.mainSession.directRooms[self.mxRoomMember.userId];
        // Check whether the room is still existing
        for (NSString* directRoomId in directRoomIds)
        {
            if ([self.mainSession roomWithRoomId:directRoomId])
            {
                [directChatsArray addObject:directRoomId];
            }
        }
    }
    
    // Complete data update and reload table view
    [super updateMemberInfo];
}

- (void)refreshUserEncryptionTrustLevel
{
    NSString *userId = self.mxRoomMember.userId;
    
    if (!userId)
    {
        return;
    }
    
    [self.mxRoom.mxSession.crypto downloadKeys:@[userId] forceDownload:YES success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap, NSDictionary<NSString *,MXCrossSigningInfo *> *crossSigningKeysMap) {
        [self.mxRoom encryptionTrustLevelForUserId:userId onComplete:^(UserEncryptionTrustLevel userEncryptionTrustLevel) {
            self.encryptionTrustLevel = userEncryptionTrustLevel;
            [self updateMemberInfo];
        }];
    } failure:^(NSError *error) {
        [self.mxRoom encryptionTrustLevelForUserId:userId onComplete:^(UserEncryptionTrustLevel userEncryptionTrustLevel) {
            self.encryptionTrustLevel = userEncryptionTrustLevel;
            [self updateMemberInfo];
        }];
    }];
}

- (BOOL)isRoomMemberCurrentUser
{
    return [self.mxRoomMember.userId isEqualToString:self.mainSession.myUser.userId];
}

- (void)startUserVerification
{
    [[AppDelegate theDelegate] presentUserVerificationForRoomMember:self.mxRoomMember session:self.mainSession completion:^{
        [self refreshUserEncryptionTrustLevel];
    }];
}

- (void)presentUserVerification
{
    UserVerificationCoordinatorBridgePresenter *userVerificationCoordinatorBridgePresenter = [[UserVerificationCoordinatorBridgePresenter alloc] initWithPresenter:self
                                                                                                                                                           session:self.mxRoom.mxSession
                                                                                                                                                            userId:self.mxRoomMember.userId
                                                                                                                                                   userDisplayName:self.mxRoomMember.displayname];
    userVerificationCoordinatorBridgePresenter.delegate = self;
    [userVerificationCoordinatorBridgePresenter start];
    self.userVerificationCoordinatorBridgePresenter = userVerificationCoordinatorBridgePresenter;
}

- (void)presentCompleteSecurity
{
    [[AppDelegate theDelegate] presentCompleteSecurityForSession:self.mainSession];
}

- (void)showRoomWithId:(NSString*)roomId
{
    Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerRoomMemberDetail;
    [[AppDelegate theDelegate] showRoom:roomId andEventId:nil withMatrixSession:self.mainSession];
}

#pragma mark - Hide/Show navigation bar border

- (void)hideNavigationBarBorder:(BOOL)isHidden
{
    // Consider the main navigation controller if the current view controller is embedded inside a split view controller.
    UINavigationController *mainNavigationController = self.navigationController;
    if (self.splitViewController && self.splitViewController.isCollapsed && self.splitViewController.viewControllers.count)
    {
        mainNavigationController = self.splitViewController.viewControllers.firstObject;
    }
    
    if (isHidden)
    {
        // The default shadow image is nil. When non-nil, this property represents a custom shadow image to show instead
        // of the default. For a custom shadow image to be shown, a custom background image must also be set with the
        // setBackgroundImage:forBarMetrics: method. If the default background image is used, then the default shadow
        // image will be used regardless of the value of this property.
        [mainNavigationController.navigationBar setShadowImage:[[UIImage alloc] init]];
        [mainNavigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
    }
    else
    {
        // Restore default navigationbar settings
        [mainNavigationController.navigationBar setShadowImage:nil];
        [mainNavigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
    }

    // Main Navigation bar opacity must follow
    self.navigationController.navigationBar.translucent = isHidden;
    mainNavigationController.navigationBar.translucent = isHidden;
}

#pragma mark - TableView data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSInteger sectionCount = 0;
    
    BOOL isOneself = NO;
    
    // Check user's power level before allowing an action (kick, ban, ...)
    MXRoomPowerLevels *powerLevels = [self.mxRoom.dangerousSyncState powerLevels];
    NSInteger memberPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mxRoomMember.userId];
    NSInteger oneSelfPowerLevel = [self.mxRoom.dangerousSyncState powerLevelOfUserWithUserID:self.mainSession.myUser.userId];
    
    [adminActionsArray removeAllObjects];
    [otherActionsArray removeAllObjects];
    
    // Consider the case of the user himself
    if (self.isRoomMemberCurrentUser)
    {
        isOneself = YES;
        
        if (self.enableLeave)
        {
            [otherActionsArray addObject:@(MXKRoomMemberDetailsActionLeave)];
        }
        
        if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomPowerLevels])
        {
            // Check whether the user is admin (in this case he may reduce his power level to become moderator or less, EXCEPT if he is the only admin).
            if (oneSelfPowerLevel >= RoomPowerLevelAdmin)
            {
                NSArray *levelValues = powerLevels.users.allValues;
                NSUInteger adminCount = 0;
                for (NSNumber *valueNumber in levelValues)
                {
                    if ([valueNumber unsignedIntegerValue] >= RoomPowerLevelAdmin)
                    {
                        adminCount ++;
                    }
                }
                
                if (adminCount > 1)
                {
                    [adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetModerator)];
                    [adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetDefaultPowerLevel)];
                }
            }
            // Check whether the user is moderator (in this case he may reduce his power level to become normal user).
            else if (oneSelfPowerLevel >= RoomPowerLevelModerator)
            {
                [adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetDefaultPowerLevel)];
            }
        }
    }
    else if (self.mxRoomMember)
    {
        // Enumerate admin actions
        switch (self.mxRoomMember.membership)
        {
            case MXMembershipInvite:
            case MXMembershipJoin:
            {
                // update power level
                if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomPowerLevels] && oneSelfPowerLevel > memberPowerLevel)
                {
                    // Check whether user is admin
                    if (oneSelfPowerLevel >= RoomPowerLevelAdmin)
                    {
                        [adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetAdmin)];
                    }
                    
                    // Check whether the member may become moderator
                    if (oneSelfPowerLevel >= RoomPowerLevelModerator && memberPowerLevel < RoomPowerLevelModerator)
                    {
                        [adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetModerator)];
                    }
                    
                    if (memberPowerLevel >= RoomPowerLevelModerator)
                    {
                        [adminActionsArray addObject:@(MXKRoomMemberDetailsActionSetDefaultPowerLevel)];
                    }
                }
                
                // Check conditions to be able to kick someone
                if (oneSelfPowerLevel >= [powerLevels kick] && oneSelfPowerLevel > memberPowerLevel)
                {
                    [adminActionsArray addObject:@(MXKRoomMemberDetailsActionKick)];
                }
                // Check conditions to be able to ban someone
                if (oneSelfPowerLevel >= [powerLevels ban] && oneSelfPowerLevel > memberPowerLevel)
                {
                    [adminActionsArray addObject:@(MXKRoomMemberDetailsActionBan)];
                }
                
                break;
            }
            case MXMembershipLeave:
            {
                // Check conditions to be able to invite someone
                if (oneSelfPowerLevel >= [powerLevels invite])
                {
                    [adminActionsArray addObject:@(MXKRoomMemberDetailsActionInvite)];
                }
                // Check conditions to be able to ban someone
                if (oneSelfPowerLevel >= [powerLevels ban] && oneSelfPowerLevel > memberPowerLevel)
                {
                    [adminActionsArray addObject:@(MXKRoomMemberDetailsActionBan)];
                }
                break;
            }
            case MXMembershipBan:
            {
                // Check conditions to be able to unban someone
                if (oneSelfPowerLevel >= [powerLevels ban] && oneSelfPowerLevel > memberPowerLevel)
                {
                    [adminActionsArray addObject:@(MXKRoomMemberDetailsActionUnban)];
                }
                break;
            }
            default:
            {
                break;
            }
        }
        
        // List the other actions
        if (self.enableVoipCall)
        {
            // Offer voip call options
            [otherActionsArray addObject:@(MXKRoomMemberDetailsActionStartVoiceCall)];
            [otherActionsArray addObject:@(MXKRoomMemberDetailsActionStartVideoCall)];
        }
        
        // Check whether the option Ignore may be presented
        if (RiotSettings.shared.roomMemberScreenShowIgnore)
        {
            // is he already ignored ?
            if (![self.mainSession isUserIgnored:self.mxRoomMember.userId])
            {
                [otherActionsArray addObject:@(MXKRoomMemberDetailsActionIgnore)];
            }
            else
            {
                [otherActionsArray addObject:@(MXKRoomMemberDetailsActionUnignore)];
            }
        }
        
        if (self.enableMention)
        {
            // Add mention option
            [otherActionsArray addObject:@(MXKRoomMemberDetailsActionMention)];
        }
    }
    
    if (self.mxRoom.summary.isEncrypted)
    {
        securityActionsArray = @[@(MXKRoomMemberDetailsActionSecurity),
                                 @(MXKRoomMemberDetailsActionSecurityInformation)];
        
    }
    else
    {
        securityActionsArray = @[@(MXKRoomMemberDetailsActionSecurity)];
    }
    
    securityIndex = adminToolsIndex = otherActionsIndex = directChatsIndex = devicesIndex = -1;
    
    
    if (securityActionsArray.count)
    {
        securityIndex = sectionCount++;
    }
    
    if (otherActionsArray.count)
    {
        otherActionsIndex = sectionCount++;
    }
    if (adminActionsArray.count)
    {
        adminToolsIndex = sectionCount++;
    }
    
    if (!isOneself)
    {
        directChatsIndex = sectionCount++;
    }
    
    if (devicesArray.count)
    {
        devicesIndex = sectionCount++;
    }
    
    return sectionCount;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section == securityIndex)
    {
        return securityActionsArray.count;
    }
    else if (section == adminToolsIndex)
    {
        return adminActionsArray.count;
    }
    else if (section == otherActionsIndex)
    {
        return otherActionsArray.count;
    }
    else if (section == directChatsIndex)
    {
        return (directChatsArray.count + 1);
    }
    else if (section == devicesIndex)
    {
        return (devicesArray.count);
    }
    
    return 0;
}

- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == securityIndex)
    {
        return [VectorL10n roomParticipantsActionSectionSecurity];
    }
    else if (section == adminToolsIndex)
    {
        return [VectorL10n roomParticipantsActionSectionAdminTools];
    }
    else if (section == otherActionsIndex)
    {
        return [VectorL10n roomParticipantsActionSectionOther];
    }
    else if (section == directChatsIndex)
    {
        return [VectorL10n roomParticipantsActionSectionDirectChats];
    }
    else if (section == devicesIndex)
    {
        return [VectorL10n roomParticipantsActionSectionDevices];
    }
    
    return nil;
}

- (NSString*)actionButtonTitle:(MXKRoomMemberDetailsAction)action
{
    NSString *title;
    
    switch (action)
    {
        case MXKRoomMemberDetailsActionInvite:
            title = [VectorL10n roomParticipantsActionInvite];
            break;
        case MXKRoomMemberDetailsActionLeave:
            title = [VectorL10n roomParticipantsActionLeave];
            break;
        case MXKRoomMemberDetailsActionKick:
            if (self.mxRoom.summary.roomType == MXRoomTypeSpace)
            {
                title = [VectorL10n spaceParticipantsActionRemove];
            }
            else
            {
                title = [VectorL10n roomParticipantsActionRemove];
            }
            break;
        case MXKRoomMemberDetailsActionBan:
            if (self.mxRoom.summary.roomType == MXRoomTypeSpace)
            {
                title = [VectorL10n spaceParticipantsActionBan];
            }
            else
            {
                title = [VectorL10n roomParticipantsActionBan];
            }
            break;
        case MXKRoomMemberDetailsActionUnban:
            title = [VectorL10n roomParticipantsActionUnban];
            break;
        case MXKRoomMemberDetailsActionIgnore:
            title = [VectorL10n roomParticipantsActionIgnore];
            break;
        case MXKRoomMemberDetailsActionUnignore:
            title = [VectorL10n roomParticipantsActionUnignore];
            break;
        case MXKRoomMemberDetailsActionSetDefaultPowerLevel:
            title = [VectorL10n roomParticipantsActionSetDefaultPowerLevel];
            break;
        case MXKRoomMemberDetailsActionSetModerator:
            title = [VectorL10n roomParticipantsActionSetModerator];
            break;
        case MXKRoomMemberDetailsActionSetAdmin:
            title = [VectorL10n roomParticipantsActionSetAdmin];
            break;
        case MXKRoomMemberDetailsActionStartChat:
            title = [VectorL10n roomParticipantsActionStartNewChat];
            break;
        case MXKRoomMemberDetailsActionStartVoiceCall:
            title = [VectorL10n roomParticipantsActionStartVoiceCall];
            break;
        case MXKRoomMemberDetailsActionStartVideoCall:
            title = [VectorL10n roomParticipantsActionStartVideoCall];
            break;
        case MXKRoomMemberDetailsActionMention:
            title = [VectorL10n roomParticipantsActionMention];
            break;
        default:
            break;
    }
    
    return title;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell;
    
    if (indexPath.section == securityIndex && indexPath.row < securityActionsArray.count)
    {
        NSNumber *actionNumber = securityActionsArray[indexPath.row];
        
        if (actionNumber.unsignedIntegerValue == MXKRoomMemberDetailsActionSecurity)
        {
            MXKTableViewCell *securityStatusCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
            
            NSString *statusText;
            
            switch (self.encryptionTrustLevel) {
                case UserEncryptionTrustLevelTrusted:
                    statusText = [VectorL10n roomParticipantsActionSecurityStatusVerified];
                    break;
                case UserEncryptionTrustLevelNotVerified:
                case UserEncryptionTrustLevelNoCrossSigning:
                {
                    if (self.isRoomMemberCurrentUser)
                    {
                        statusText = [VectorL10n roomParticipantsActionSecurityStatusCompleteSecurity];
                    }
                    else
                    {
                        statusText = [VectorL10n roomParticipantsActionSecurityStatusVerify];
                    }
                }
                    break;
                case UserEncryptionTrustLevelWarning:
                    statusText = [VectorL10n roomParticipantsActionSecurityStatusWarning];
                    break;
                default:
                    statusText = [VectorL10n roomParticipantsActionSecurityStatusLoading];
                    break;
            }
            
            securityStatusCell.imageView.image = [EncryptionTrustLevelBadgeImageHelper userBadgeImageFor:self.encryptionTrustLevel];
            
            securityStatusCell.textLabel.numberOfLines = 1;
            securityStatusCell.textLabel.font = [UIFont systemFontOfSize:16.0];
            securityStatusCell.textLabel.textColor = ThemeService.shared.theme.textPrimaryColor;
            securityStatusCell.textLabel.text = statusText;
            
            securityStatusCell.backgroundColor = ThemeService.shared.theme.backgroundColor;
            securityStatusCell.contentView.backgroundColor = [UIColor clearColor];
            securityStatusCell.selectionStyle = UITableViewCellSelectionStyleNone;
            [securityStatusCell vc_setAccessoryDisclosureIndicatorWithCurrentTheme];
            
            cell = securityStatusCell;
        }
        else if (actionNumber.unsignedIntegerValue == MXKRoomMemberDetailsActionSecurityInformation)
        {
            MXKTableViewCell *encryptionInfoCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
            
            NSMutableString *encryptionInformation = [NSMutableString new];
            
            switch (self.encryptionTrustLevel) {
                case UserEncryptionTrustLevelWarning:
                case UserEncryptionTrustLevelNotVerified:
                case UserEncryptionTrustLevelNoCrossSigning:
                case UserEncryptionTrustLevelTrusted:
                {
                    NSString *info = (self.mxRoom.isDirect) ?
                    [VectorL10n roomParticipantsSecurityInformationRoomEncryptedForDm] :
                    [VectorL10n roomParticipantsSecurityInformationRoomEncrypted];
                    [encryptionInformation appendString:info];
                }
                    break;
                case UserEncryptionTrustLevelNone:
                    {
                        NSString *info = (self.mxRoom.isDirect) ?
                        [VectorL10n roomParticipantsSecurityInformationRoomNotEncryptedForDm] :
                        [VectorL10n roomParticipantsSecurityInformationRoomNotEncrypted];
                        [encryptionInformation appendString:info];
                    }
                    break;
                case UserEncryptionTrustLevelUnknown:
                    [encryptionInformation appendString:[VectorL10n roomParticipantsSecurityLoading]];
                    break;
                default:
                    break;
            }
            
            if (encryptionInformation.length)
            {
                [encryptionInformation appendString:@"\n"];
            }
            
            encryptionInfoCell.textLabel.backgroundColor = [UIColor clearColor];
            encryptionInfoCell.textLabel.numberOfLines = 0;
            encryptionInfoCell.textLabel.text = encryptionInformation;
            encryptionInfoCell.textLabel.font = [UIFont systemFontOfSize:14.0];
            encryptionInfoCell.textLabel.textColor = ThemeService.shared.theme.headerTextPrimaryColor;
            
            encryptionInfoCell.selectionStyle = UITableViewCellSelectionStyleNone;
            encryptionInfoCell.accessoryType = UITableViewCellAccessoryNone;
            encryptionInfoCell.contentView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
            encryptionInfoCell.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;

            //  extend background color to safe area
            UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
            bgView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor;
            encryptionInfoCell.backgroundView = bgView;
            
            cell = encryptionInfoCell;
        }
    }
    else if (indexPath.section == adminToolsIndex || indexPath.section == otherActionsIndex)
    {
        TableViewCellWithButton *cellWithButton = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithButton defaultReuseIdentifier] forIndexPath:indexPath];
        
        NSNumber *actionNumber;
        if (indexPath.section == adminToolsIndex && indexPath.row < adminActionsArray.count)
        {
            actionNumber = adminActionsArray[indexPath.row];
        }
        else if (indexPath.section == otherActionsIndex && indexPath.row < otherActionsArray.count)
        {
            actionNumber = otherActionsArray[indexPath.row];
        }
        
        if (actionNumber)
        {
            NSString *title = [self actionButtonTitle:actionNumber.unsignedIntegerValue];
            
            [cellWithButton.mxkButton setTitle:title forState:UIControlStateNormal];
            [cellWithButton.mxkButton setTitle:title forState:UIControlStateHighlighted];
            
            if (actionNumber.unsignedIntegerValue == MXKRoomMemberDetailsActionKick)
            {
                [cellWithButton.mxkButton setTitleColor:ThemeService.shared.theme.warningColor forState:UIControlStateNormal];
                [cellWithButton.mxkButton setTitleColor:ThemeService.shared.theme.warningColor forState:UIControlStateHighlighted];
            }
            else
            {
                [cellWithButton.mxkButton setTitleColor:ThemeService.shared.theme.textPrimaryColor forState:UIControlStateNormal];
                [cellWithButton.mxkButton setTitleColor:ThemeService.shared.theme.textPrimaryColor forState:UIControlStateHighlighted];
            }
            
            [cellWithButton.mxkButton addTarget:self action:@selector(onActionButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
            
            cellWithButton.mxkButton.tag = actionNumber.unsignedIntegerValue;
        }
        
        cell = cellWithButton;
    }
    else if (indexPath.section == directChatsIndex)
    {
        RoomTableViewCell *roomCell = [tableView dequeueReusableCellWithIdentifier:[RoomTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
        
        if (indexPath.row < directChatsArray.count)
        {
            MXRoom *room = [self.mainSession roomWithRoomId:directChatsArray[indexPath.row]];
            if (room)
            {
                [roomCell render:room];
            }
        }
        else
        {
            roomCell.avatarImageView.image = AssetImages.startChat.image;
            roomCell.avatarImageView.defaultBackgroundColor = [UIColor clearColor];
            roomCell.avatarImageView.userInteractionEnabled = NO;
            roomCell.titleLabel.text = [VectorL10n roomParticipantsActionStartNewChat];
        }
        
        cell = roomCell;
    }
    else if (indexPath.section == devicesIndex)
    {
        DeviceTableViewCell *deviceCell = [tableView dequeueReusableCellWithIdentifier:[DeviceTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
        deviceCell.selectionStyle = UITableViewCellSelectionStyleNone;
        
        if (indexPath.row < devicesArray.count)
        {
            MXDeviceInfo *deviceInfo = devicesArray[indexPath.row];
            [deviceCell render:deviceInfo];
            deviceCell.delegate = self;
            
            // Display here the Verify and Block buttons except if the device is the current one.
            deviceCell.verifyButton.hidden = deviceCell.blockButton.hidden = [deviceInfo.deviceId isEqualToString:self.mxRoom.mxSession.matrixRestClient.credentials.deviceId];
        }
        cell = deviceCell;
    }
    else
    {
        // Create a fake cell to prevent app from crashing
        cell = [[UITableViewCell alloc] init];
    }
    
    return cell;
}

#pragma mark - UITableView delegate

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
{
    cell.backgroundColor = ThemeService.shared.theme.backgroundColor;
    
    // Update the selected background view
    if (ThemeService.shared.theme.selectedBackgroundColor)
    {
        cell.selectedBackgroundView = [[UIView alloc] init];
        cell.selectedBackgroundView.backgroundColor = ThemeService.shared.theme.selectedBackgroundColor;
    }
    else
    {
        if (tableView.style == UITableViewStylePlain)
        {
            cell.selectedBackgroundView = nil;
        }
        else
        {
            cell.selectedBackgroundView.backgroundColor = nil;
        }
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return TABLEVIEW_SECTION_HEADER_HEIGHT;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    if (indexPath.section == securityIndex)
    {
        if (self.encryptionTrustLevel == UserEncryptionTrustLevelNotVerified)
        {
            if (self.isRoomMemberCurrentUser)
            {
                [self presentCompleteSecurity];
            }
            else
            {
                [self startUserVerification];
            }
        }
        else
        {
            [self presentUserVerification];
        }
    }
    else if (indexPath.section == directChatsIndex)
    {
        if (indexPath.row < directChatsArray.count)
        {
            // Open this room
            [self showRoomWithId:directChatsArray[indexPath.row]];
        }
        else
        {
            // Create a new direct chat with the member
            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            button.tag = MXKRoomMemberDetailsActionStartChat;
            
            [super onActionButtonPressed:button];
        }
    }
    else
    {
        UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
        if (selectedCell && [selectedCell isKindOfClass:TableViewCellWithButton.class])
        {
            TableViewCellWithButton *cell = (TableViewCellWithButton*)selectedCell;
            
            [self onActionButtonPressed:cell.mxkButton];
        }
    }
    
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

#pragma mark - Action

- (void)onActionButtonPressed:(id)sender
{
    if ([sender isKindOfClass:[UIButton class]])
    {
        // already a pending action
        if ([self hasPendingAction])
        {
            return;
        }
        
        UIButton *button = (UIButton*)sender;
        
        switch (button.tag)
        {
            case MXKRoomMemberDetailsActionSetDefaultPowerLevel:
            {
                [self.mxRoom state:^(MXRoomState *roomState) {
                    [self setPowerLevel:roomState.powerLevels.usersDefault promptUser:YES];
                }];
                break;
            }
            case MXKRoomMemberDetailsActionSetModerator:
            {
                [self setPowerLevel:RoomPowerLevelModerator promptUser:YES];
                break;
            }
            case MXKRoomMemberDetailsActionSetAdmin:
            {
                [self setPowerLevel:RoomPowerLevelAdmin promptUser:YES];
                break;
            }
            case MXKRoomMemberDetailsActionBan:
            {
                __weak typeof(self) weakSelf = self;
                
                // Ban
                currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomEventActionBanPromptReason]
                                                                   message:nil
                                                            preferredStyle:UIAlertControllerStyleAlert];
                
                [currentAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
                    textField.secureTextEntry = NO;
                    textField.placeholder = nil;
                    textField.keyboardType = UIKeyboardTypeDefault;
                }];
                
                [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                                                 style:UIAlertActionStyleDefault
                                                               handler:^(UIAlertAction * action) {
                                                                   
                                                                   if (weakSelf)
                                                                   {
                                                                       typeof(self) self = weakSelf;
                                                                       self->currentAlert = nil;
                                                                   }
                                                                   
                                                               }]];
                
                [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n ban]
                                                                 style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
                                                                     
                                                                     if (weakSelf)
                                                                     {
                                                                         typeof(self) self = weakSelf;

                                                                         NSString *text = [self->currentAlert textFields].firstObject.text;

                                                                         self->currentAlert = nil;
                                                                         
                                                                         [self startActivityIndicator];
                                                                         
                                                                         // kick user
                                                                         [self.mxRoom banUser:self.mxRoomMember.userId reason:text success:^{
                                                                             
                                                                             __strong __typeof(weakSelf)self = weakSelf;
                                                                             [self stopActivityIndicator];
                                                                             
                                                                         } failure:^(NSError *error) {
                                                                             
                                                                             __strong __typeof(weakSelf)self = weakSelf;
                                                                             [self stopActivityIndicator];
                                                                             
                                                                             MXLogDebug(@"[RoomMemberDetailVC] Ban user (%@) failed", self.mxRoomMember.userId);
                                                                             //Alert user
                                                                             [[AppDelegate theDelegate] showErrorAsAlert:error];
                                                                             
                                                                         }];
                                                                     }
                                                                     
                                                                 }]];
                
                [currentAlert mxk_setAccessibilityIdentifier:@"RoomMemberDetailsVCBanAlert"];
                [self presentViewController:currentAlert animated:YES completion:nil];
                break;
            }
            case MXKRoomMemberDetailsActionKick:
            {
                __weak typeof(self) weakSelf = self;
                
                // Kick
                currentAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomEventActionKickPromptReason]
                                                                   message:nil
                                                            preferredStyle:UIAlertControllerStyleAlert];
                
                [currentAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
                    textField.secureTextEntry = NO;
                    textField.placeholder = nil;
                    textField.keyboardType = UIKeyboardTypeDefault;
                }];
                
                [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
                                                                 style:UIAlertActionStyleDefault
                                                               handler:^(UIAlertAction * action) {
                                                                   
                                                                   if (weakSelf)
                                                                   {
                                                                       typeof(self) self = weakSelf;
                                                                       self->currentAlert = nil;
                                                                   }
                                                                   
                                                               }]];
                
                [currentAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n remove]
                                                                 style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
                                                                   
                                                                   if (weakSelf)
                                                                   {
                                                                       typeof(self) self = weakSelf;

                                                                       NSString *text = [self->currentAlert textFields].firstObject.text;

                                                                       self->currentAlert = nil;
                                                                       
                                                                       [self startActivityIndicator];
                                                                       
                                                                       // kick user
                                                                       [self.mxRoom kickUser:self.mxRoomMember.userId reason:text success:^{
                                                                           
                                                                           __strong __typeof(weakSelf)self = weakSelf;
                                                                           [self stopActivityIndicator];
                                                                           
                                                                       } failure:^(NSError *error) {
                                                                           
                                                                           __strong __typeof(weakSelf)self = weakSelf;
                                                                           [self stopActivityIndicator];
                                                                           
                                                                           MXLogDebug(@"[RoomMemberDetailVC] Removing user (%@) failed", self.mxRoomMember.userId);
                                                                           //Alert user
                                                                           [[AppDelegate theDelegate] showErrorAsAlert:error];
                                                                           
                                                                       }];
                                                                   }
                                                                   
                                                               }]];
                
                [currentAlert mxk_setAccessibilityIdentifier:@"RoomMemberDetailsVCKickAlert"];
                [self presentViewController:currentAlert animated:YES completion:nil];
                break;
            }
            default:
            {
                [super onActionButtonPressed:sender];
            }
        }
    }
}

- (void)handleTapGesture:(UITapGestureRecognizer*)tapGestureRecognizer
{
    UIView *view = tapGestureRecognizer.view;
    
    if (view == memberTitleView.memberAvatarMask || view == self.roomMemberAvatarMask)
    {
        MXWeakify(self);
        
        // Show the avatar in full screen
        __block MXKImageView * avatarFullScreenView = [[MXKImageView alloc] initWithFrame:CGRectZero];
        avatarFullScreenView.stretchable = YES;

        [avatarFullScreenView setRightButtonTitle:[VectorL10n ok]
                                          handler:^(MXKImageView* imageView, NSString* buttonTitle) {
                                              
                                              MXStrongifyAndReturnIfNil(self);
                                              [avatarFullScreenView dismissSelection];
                                              [avatarFullScreenView removeFromSuperview];
                                              
                                              avatarFullScreenView = nil;
                                              
                                              // Restore the status bar
                                              self->isStatusBarHidden = NO;
                                              [self setNeedsStatusBarAppearanceUpdate];
                                          }];

        [avatarFullScreenView setImageURI:self.mxRoomMember.avatarUrl
                                 withType:nil
                      andImageOrientation:UIImageOrientationUp
                             previewImage:self.memberThumbnail.image
                             mediaManager:self.mainSession.mediaManager];

        [avatarFullScreenView showFullScreen];
        
        // Hide the status bar
        isStatusBarHidden = YES;
        // Trigger status bar update
        [self setNeedsStatusBarAppearanceUpdate];
    }
}

#pragma mark - 

- (void)deviceTableViewCell:(DeviceTableViewCell*)deviceTableViewCell updateDeviceVerification:(MXDeviceVerification)verificationStatus
{
    if (verificationStatus == MXDeviceVerified)
    {
        keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:self.mainSession];
        keyVerificationCoordinatorBridgePresenter.delegate = self;

        [keyVerificationCoordinatorBridgePresenter presentFrom:self otherUserId:deviceTableViewCell.deviceInfo.userId otherDeviceId:deviceTableViewCell.deviceInfo.deviceId animated:YES];
    }
    else
    {
        [self.mxRoom.mxSession.crypto setDeviceVerification:verificationStatus
                                                  forDevice:deviceTableViewCell.deviceInfo.deviceId
                                                     ofUser:self.mxRoomMember.userId
                                                    success:^{
                                                        [self updateMemberInfo];
                                                    } failure:nil];
    }
}

#pragma mark - RoomMemberTitleViewDelegate

- (void)roomMemberTitleViewDidLayoutSubview:(RoomMemberTitleView*)titleView
{
    [self viewDidLayoutSubviews];
}

#pragma mark - KeyVerificationCoordinatorBridgePresenterDelegate

- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter *)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId
{
    [self refreshUserEncryptionTrustLevel];
    [self dismissKeyVerificationCoordinatorBridgePresenter];
}

- (void)keyVerificationCoordinatorBridgePresenterDelegateDidCancel:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
{
    [self dismissKeyVerificationCoordinatorBridgePresenter];
}

- (void)dismissKeyVerificationCoordinatorBridgePresenter
{
    [keyVerificationCoordinatorBridgePresenter dismissWithAnimated:YES completion:nil];
    keyVerificationCoordinatorBridgePresenter = nil;
}

#pragma mark - UserVerificationCoordinatorBridgePresenterDelegate

- (void)userVerificationCoordinatorBridgePresenterDelegateDidComplete:(UserVerificationCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
    [self refreshUserEncryptionTrustLevel];
}

@end
